package com.cictec.middleware.tde.rm;

import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.apache.mina.core.future.CloseFuture;
import org.apache.mina.core.future.IoFuture;
import org.apache.mina.core.future.IoFutureListener;
import org.apache.mina.core.service.IoService;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.cictec.middleware.commons.utils.DateUtils;
import com.cictec.middleware.feign.distribute.MiddlewareDeviceService;

/**
 * mina通用session管理，所以放到core中,目前由于业务耦合，暂时放在这里管理
 * 
 * @author Administrator
 *
 */
@Component
public class SessionManager {

	private static Logger logger = LoggerFactory.getLogger(SessionManager.class);

	private final AttributeKey CONNECT_TIME = new AttributeKey(getClass(), "ConnectTime");
	private final AttributeKey TERMINAL_ID = new AttributeKey(getClass(), "TerminalId");
	private final AttributeKey SERIAL_NUMBER = new AttributeKey(getClass(), "SerialNumber");
	/** 终端数据传输协议 【rm:锐明、808、809】*/
	private final AttributeKey TERMINAL_PROTOCOL = new AttributeKey(getClass(), "TerminalProtocol");// 终端数据传输协议

	/**
	 * 所有的连接到平台的Session
	 */
	private ConcurrentMap<Long, IoSession> sessions = new ConcurrentHashMap<Long, IoSession>();

	@Autowired
	private MiddlewareDeviceService middlewareDeviceService;
	private IoService ioService;
	private boolean allowRepeatConnectOneAddress = true;
	private boolean closeOldConnectWhenRepeatConnect = true;

	/**
	 * 获取所有的Session
	 * 
	 * @return
	 */
	public Collection<IoSession> getAllSession() {
		return sessions.values();
	}

	public void showActiveSessions() {

		if (logger.isDebugEnabled()) {
			logger.debug("当前SessionManager的连接会话：");

			for (IoSession ses : sessions.values()) {
				String createTime = DateUtils.formatDateTimes(new Date(ses.getCreationTime()));
				String lastReadTime = DateUtils.formatDateTimes(new Date(ses.getLastReadTime()));
				String lastWriteTime = DateUtils.formatDateTimes(new Date(ses.getLastWriteTime()));
				String addr = ses.getRemoteAddress() == null ? "" : ses.getRemoteAddress().toString();

				logger.debug("【SessionManager】 Session {} ID {} IP:{} crt:{} lst rad:{} lst wrt:{} 关闭中 {} 连接 {}",
						ses.getId(), ses.getAttribute(TERMINAL_ID), addr, createTime, lastReadTime, lastWriteTime,
						ses.isClosing(), ses.isConnected());
			}
		}
	}

	/**
	 * 关闭僵尸Session。连接超过1分钟并且没有通过鉴权的Sessoin。
	 */
	public void colseZombieSession() {

		/*
		 * for (IoSession ses : sessions.values()) { if
		 * ((System.currentTimeMillis() - ses.getLastReadTime()) / 1000 > 120) {
		 * String createTime = DateUtils.timesFormat(new
		 * Date(ses.getCreationTime())); String lastReadTime =
		 * DateUtils.timesFormat(new Date(ses.getLastReadTime())); String
		 * lastWriteTime = DateUtils.timesFormat(new
		 * Date(ses.getLastWriteTime())); String addr = ses.getRemoteAddress()
		 * == null ? "" : ses.getRemoteAddress().toString(); logger.
		 * debug("发现僵尸会话，立刻关闭 Session {} ID {} IP:{} crt:{} lst rad:{} lst wrt:{} 关闭中 {} 连接 {}"
		 * , ses.getId(), ses.getAttribute(TERMINAL_ID), addr, createTime,
		 * lastReadTime, lastWriteTime, ses.isClosing(), ses.isConnected());
		 * 
		 * closeSession(ses, true);
		 * 
		 * } }
		 * 
		 * showActiveSessions();
		 */
	}

	/** 终端出厂序列号 */
	public void setSerialNumber(IoSession session, String sn) {
		session.setAttribute(SERIAL_NUMBER, sn);
	}

	/** 终端出厂序列号 */
	public String getSerialNumber(IoSession session) {
		return (String) session.getAttribute(SERIAL_NUMBER);
	}

	public void closeSession(long sessionId, boolean immediately) {
		IoSession session = sessions.get(sessionId);
		if (session != null) {
			closeSession(session);
		} else {
			logger.debug("【SessionManager】关闭Session 无法根据Id找到对应的 Session {} ", sessionId);
		}
	}

	public CloseFuture closeSession(IoSession session) {
		logger.debug("【SessionManager】关闭连接会话 Session {}", session.getId());
		CloseFuture closeFuture = session.closeNow();
		closeFuture.addListener(new IoFutureListener<IoFuture>() {
			@Override
			public void operationComplete(IoFuture future) {
				logger.debug("【SessionManager】连接会话关闭完成 Session {}", future.getSession().getId());
			}
		});
		return closeFuture;
	}

	/**
	 * 断开所有的连接会话
	 */
	public void closeAll() {
		for (IoSession session : sessions.values()) {
			CloseFuture closeFuture = closeSession(session);
			try {
				closeFuture.await();
			} catch (InterruptedException e) {
			}
		}
	}

	/**
	 * Session是否通过鉴权【是否包含terminalId】
	 * 
	 * @param session
	 * @return
	 */
	public boolean isAuthenticated(IoSession session) {
		return session.getAttribute(TERMINAL_ID) == null ? false : true;
	}

	public void registerSession(IoSession session) {

		InetSocketAddress isa = (InetSocketAddress) session.getRemoteAddress();

		if (!allowRepeatConnectOneAddress) {
			for (IoSession s : sessions.values()) {
				InetSocketAddress addr = (InetSocketAddress) s.getRemoteAddress();
				if (addr != null && addr.getAddress().getHostAddress().equals(isa.getAddress().getHostAddress())) {
					if (s.isConnected() && !s.isClosing()) {
						// 发现30秒内有数据上传，判定重复连接。
						logger.debug("【SessionManager】发现地址为 {} 的主机重复连接。", isa.getAddress().getHostAddress());
						if (!closeOldConnectWhenRepeatConnect) {
							closeSession(session);
							return;
						} else {
							closeSession(s);
						}
					}
				}
			}
		}
		session.setAttributeIfAbsent(CONNECT_TIME, new Date());
		sessions.put(session.getId(), session);
		logger.debug("【SessionManager】注册新建Session {} {}", session.getId(), session.getRemoteAddress().toString());
		logger.debug("【SessionManager】管理连接总数为：{}", getAllSession().size());
	}

	public void unregisterSession(IoSession session) {

		sessions.remove(session.getId());
		String tId = (String) session.getAttribute(TERMINAL_ID);
		// logger.debug("取消注册 SessionId {} address:{} TERMINAL_ID:{}
		// ",session.getId(),session.getRemoteAddress().toString(), tId);
		if (tId == null) {
			// 如果terminalId 为空 表示 调用 closeSession(session)方法
			logger.debug("【SessionManager】取消注册 Session {} ，该session中没有设置设备编号", session.getId());
		}

		if (tId != null && getSessionByTerminalId(tId) == null) {
			logger.debug("【SessionManager】取消注册 Session {} TERMINAL_ID:{} ", session.getId(), tId);
			try {
				// 中间件注销该设备，离线
				middlewareDeviceService.deviceDisConnect(tId);

			} catch (Exception e) {
				e.printStackTrace();
			}

		}

	}

	public void tmpToRegistered(long sessionId, String terminalId) {
		IoSession session = sessions.get(sessionId);
		if (session != null) {
			tmpToRegistered(session, terminalId);
		} else {
			logger.debug("【SessionManager】临时Session 转注册Session 无法根据Id找到对应的 Session {} ", sessionId);
		}
	}

	public void tmpToRegistered(IoSession session, String terminalId) {
		IoSession oldSession = getSessionByTerminalId(terminalId);
		if (oldSession != null && session.getId() != oldSession.getId()) {
			logger.debug("【SessionManager】发现终端 {} 之前的Session 立即关闭.");
			oldSession.closeNow();
		}

		logger.debug("【SessionManager】设置session TERMINAL_ID:{}", terminalId);
		session.setAttribute(TERMINAL_ID, terminalId);
	}

	public boolean hasSession(String termianlId) {
		for (IoSession session : sessions.values()) {
			String tId = (String) session.getAttribute(TERMINAL_ID);
			if (tId != null && tId.equals(termianlId)) {
				return true;
			}
		}
		return false;
	}
	

	public IoSession getSessionByTerminalId(String terminalId) {
		for (IoSession session : sessions.values()) {
			String _terminalId = (String) session.getAttribute(TERMINAL_ID);
			if (_terminalId != null && _terminalId.equals(terminalId) && !session.isClosing()
					&& session.isConnected()) {
				return session;
			}
		}
		return null;
	}

	// public void setBusInstance(IoSession session, BusInstance busInstance) {
	// session.setAttribute(REALTIME_BUS, busInstance);
	// }
	//
	// public BusInstance getBusInstance(IoSession session) {
	// return (BusInstance) session.getAttribute(REALTIME_BUS);
	// }

	public String getTerminalId(IoSession session) {
		return (String) session.getAttribute(TERMINAL_ID);
	}

	
	/**
	 * 根据设备编号获取当前设备使用的数据传输协议
	 * @param devCode
	 * @return
	 */
	public String getProtocolByTerminalId(String terminalId){
		IoSession session = getSessionByTerminalId(terminalId);
		return (String) session.getAttribute(TERMINAL_PROTOCOL);
	}
	
	/**
	 * 如果不存在协议标识，添加
	 * @param session
	 * @param protocol
	 */
	public void setProtocolByTerminalId(IoSession session, String protocol){
		if(!session.containsAttribute(TERMINAL_PROTOCOL)){
			session.setAttribute(TERMINAL_PROTOCOL, protocol);
//			onlineDeviceManager.deviceConnect(protocol, String.valueOf(session.getAttribute(TERMINAL_ID)), "", String.valueOf(session.getId()), session.getRemoteAddress().toString());
		}
	}
	
	public IoService getIoService() {
		return ioService;
	}

	public void setIoService(IoService ioService) {
		this.ioService = ioService;
	}

	public IoSession getSessionById(Long id) {
		return sessions.get(id);
	}

	public boolean isAllowRepeatConnectOneAddress() {
		return allowRepeatConnectOneAddress;
	}

	public void setAllowRepeatConnectOneAddress(boolean allowRepeatConnectOneAddress) {
		this.allowRepeatConnectOneAddress = allowRepeatConnectOneAddress;
	}

}
